/*
 * This file is part of the Sx Framework Library.
 * 
 * Copyright (C) 2013 University of Colorado Denver
 * <min.choi@ucdenver.edu> <shane.transue@ucdenver.edu>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */
#ifndef SX_HASHMAP_H
#define SX_HASHMAP_H

#include <unordered_map>

namespace Sx {
namespace Util {

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
class HashMap {
public:
	typedef std::tr1::unordered_map<Key, Value, HashFunction, Comparitor> HashMapType;
	typedef typename HashMapType::iterator HashMapIterator;
	typedef typename HashMapType::const_iterator ConstHashMapIterator;
  
	HashMap();
	virtual ~HashMap();

	bool isEmpty() const;
	bool contains(const Key& key) const;

	void add(Key key, Value value);
	void put(Key key, Value value);

	bool remove(Key key);
	unsigned int size() const;

	void clear();
	void empty();

	HashMapIterator find(Key key);
	HashMapIterator begin();
	HashMapIterator end();
	ConstHashMapIterator begin() const;
	ConstHashMapIterator end() const;

	const Value& getValue(const Key& key) const;
  
protected:
	HashMapType imp;
};

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
HashMap<Key, Value, HashFunction, Comparitor>::HashMap() {
	this->imp = std::tr1::unordered_map<Key, Value, HashFunction, Comparitor>();
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
HashMap<Key, Value, HashFunction, Comparitor>::~HashMap() {}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
bool HashMap<Key, Value, HashFunction, Comparitor>::isEmpty() const {
	if ( this->imp.size() == 0 ) return true;
	return false;
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
bool HashMap<Key, Value, HashFunction, Comparitor>::contains(const Key& key) const {
	ConstHashMapIterator i = this->imp.find(key);
	if ( i != this->imp.end() ) return true;
	return false;
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
void HashMap<Key, Value, HashFunction, Comparitor>::add(Key key, Value value) {
	this->imp.insert(std::make_pair(key, value));
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
void HashMap<Key, Value, HashFunction, Comparitor>::put(Key key, Value value) {
	this->add(key ,value);
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
bool HashMap<Key, Value, HashFunction, Comparitor>::remove(Key key) {
	this->imp.erase(key);
	return true;
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
unsigned int HashMap<Key, Value, HashFunction, Comparitor>::size() const {
	return this->imp.size();
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
void HashMap<Key, Value, HashFunction, Comparitor>::clear() {
	this->imp.erase(this->imp.begin(), this->imp.end());
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
void HashMap<Key, Value, HashFunction, Comparitor>::empty() {
	this->clear();
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
typename HashMap<Key, Value, HashFunction, Comparitor>::HashMapIterator HashMap<Key, Value, HashFunction, Comparitor>::find(Key key) {
	return this->imp.find(key);
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
typename HashMap<Key, Value, HashFunction, Comparitor>::HashMapIterator HashMap<Key, Value, HashFunction, Comparitor>::begin() {
	return this->imp.begin();
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
typename HashMap<Key, Value, HashFunction, Comparitor>::HashMapIterator HashMap<Key, Value, HashFunction, Comparitor>::end() {
	return this->imp.end();
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
typename HashMap<Key, Value, HashFunction, Comparitor>::ConstHashMapIterator HashMap<Key, Value, HashFunction, Comparitor>::begin() const {
	return this->imp.begin();
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
typename HashMap<Key, Value, HashFunction, Comparitor>::ConstHashMapIterator HashMap<Key, Value, HashFunction, Comparitor>::end() const {
	return this->imp.end();
}

template <typename Key, typename Value, typename HashFunction, typename Comparitor>
const Value& HashMap<Key, Value, HashFunction, Comparitor>::getValue(const Key& key) const {
	return this->imp.find(key)->second;
}

}

}

#endif
